/*
 * Copyright 2009-2010 Nanjing RedOrange ltd (http://www.red-orange.cn)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package redora.client.ui;

import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.client.ui.*;
import redora.client.Persistable;
import redora.client.mvp.ClientFactory;
import redora.client.mvp.EditPlace;
import redora.client.mvp.FindEvent;

import java.util.logging.Logger;

import static com.google.gwt.safehtml.shared.SafeHtmlUtils.htmlEscape;
import static java.util.logging.Level.INFO;
import static redora.client.Persistable.Scope.List;

/**
 * A widget that produces a popup (when clicked) with a list of Scope.List records
 * queried from given parentId and defaultFinder.<br>
 * The widget will either show '?' or the number of records in pre-mentioned
 * query. If the query results in 0 records, the popup is suppressed.<br>
 * The records in the popup grid are clickable. When clicked, focus will move
 * to the EditPlace of clicked item. Therefor this widget is probably only really usable
 * in the showcase application.<br>
 * The widget uses the cache service and has listeners on it's members. When
 * a member of the list is updated elsewhere, the change will synced.<br>
 * The popup and the grid are styled as redoraListPopup.
 * @author Nanjing Redorange (www.red-orange.cn)
 */
public class ListPopupCell<T extends Persistable> extends AbstractCell<String> {
    static Logger l = Logger.getLogger("ListPopupCell");

    static RedoraResource redoraResource = GWT.create(RedoraResource.class);

    Popup popup;
    final int defaultFinder;
    String url;
    final ClientFactory clientFactory;
    final Class<? extends Persistable> childClass;

    @Override
    public void render(Context context, String s, SafeHtmlBuilder sb) {
        url = clientFactory.getLocator().locateService(childClass).url(defaultFinder, (Long)context.getKey());
        String label = clientFactory.getLocator().locateService(childClass).useCache(url)
                ? Integer.toString(clientFactory.getLocator().locateService(childClass).cache(url).length)
                : "?";
        sb.appendHtmlConstant("<div>");
        sb.append(SafeHtmlUtils.fromSafeConstant(label));
        sb.appendHtmlConstant("</div>");
    }

    public static abstract class PopupListColumn<T  extends Persistable> extends Column<T, String> {
        public PopupListColumn(int defaultFinder, Class<? extends Persistable> childClass) {
            super(new ListPopupCell<T>(defaultFinder, childClass));
        }
    }

    public ListPopupCell(int defaultFinder, Class<? extends Persistable> childClass) {
        super("click");
        this.clientFactory = GWT.create(ClientFactory.class);
        this.childClass = childClass;
        this.defaultFinder = defaultFinder;

        bind();
    }

    @Override
    public void onBrowserEvent(Context context, Element parent, String value, NativeEvent event, ValueUpdater<String> valueUpdater) {
        super.onBrowserEvent(context, parent, value, event, valueUpdater);

        if ("click".equals(event.getType())) {
            popup = new Popup();
            RootPanel.get().add(popup);
            url = clientFactory.getLocator().locateService(childClass).url(defaultFinder, (Long)context.getKey());
            clientFactory.getLocator().locateService(childClass).finder(url, List);
            popup.setPopupPosition(event.getClientX(), event.getClientY());
            popup.show();
        }
    }

    private void bind() {
        clientFactory.getEventBus().addHandler(FindEvent.TYPE,
                new FindEvent.Handler() {
                    @Override
                    public void onSuccess(FindEvent event) {
                        if (event.wasMe(childClass, url)) {
                            l.log(INFO, "Processing " + event.results.length + " FindEvent results for " + childClass + ": " + event.finderKey);
                            popup.setRows(event.results);
                        }
                    }
                });
    }

    class Popup extends PopupPanel {
        final Grid grid;

        public Popup() {
            super(true);
            setStyleName(redoraResource.css().redoraListPopup());
            setAnimationEnabled(true);
            setAutoHideEnabled(true);
            final ScrollPanel panel = new ScrollPanel();
            panel.setWidth("100%");
            add(panel);

            grid = new Grid();
            grid.addStyleName(redoraResource.css().redoraListPopup());
            panel.add(grid);
        }

        public void setRows(Long[] ids) {
            grid.clear();
            if (ids.length == 0) {
                hide();
            } else {
                grid.resize(ids.length, 1);
                for (int i = 0; i < ids.length; i++) {
                    Anchor link = new Anchor(htmlEscape(
                            clientFactory.getLocator().locateService(childClass).cache(ids[i]).toListString()));
                    link.setHref(new EditPlace(childClass, ids[i]).toString());
                    grid.setWidget(i, 0, link);
                }
            }
        }
    }
}
